use std::sync::Arc;
use rayon::prelude::*;
use super::simd_advanced::{SimdError, SimdResult};

#[cfg(target_arch = "x86_64")]
use std::arch::x86_64::*;

/// 成交量数据结构
#[derive(Debug, Clone)]
pub struct VolumeData {
    pub close: Vec<f64>,
    pub volume: Vec<f64>,
}

/// OBV计算结果
#[derive(Debug)]
pub struct ObvResult {
    pub obv: Vec<f64>,
    pub obv_ema: Option<Vec<f64>>, // 可选的OBV移动平均
}

impl ObvResult {
    /// 创建指定大小的OBV结果容器
    fn with_capacity(size: usize) -> Self {
        ObvResult {
            obv: Vec::with_capacity(size),
            obv_ema: None,
        }
    }

    /// 验证结果的有效性
    fn validate(&self) -> SimdResult<()> {
        if let Some(ref ema) = self.obv_ema {
            if ema.len() != self.obv.len() {
                return Err(SimdError::ComputationError(
                    "Inconsistent lengths in OBV result vectors".to_string()
                ));
            }
        }
        Ok(())
    }
}

/// 验证OBV计算的输入参数
fn validate_obv_inputs(data: &VolumeData, ema_period: Option<usize>) -> SimdResult<()> {
    let len = data.close.len();

    // 检查数据长度
    if len == 0 {
        return Err(SimdError::InvalidInputLength(
            "Input arrays are empty".to_string()
        ));
    }

    // 检查数组长度一致性
    if len != data.volume.len() {
        return Err(SimdError::InvalidInputLength(
            "Close price and volume arrays have inconsistent lengths".to_string()
        ));
    }

    // 验证成交量数据有效性
    for (i, &vol) in data.volume.iter().enumerate() {
        if vol < 0.0 {
            return Err(SimdError::InvalidInputLength(format!(
                "Negative volume found at index {}: {}", i, vol
            )));
        }
    }

    // 检查EMA周期参数（如果提供）
    if let Some(period) = ema_period {
        if period == 0 {
            return Err(SimdError::InvalidInputLength(
                "EMA period must be greater than 0".to_string()
            ));
        }
        if period > len {
            return Err(SimdError::InvalidInputLength(format!(
                "EMA period {} exceeds data length {}", period, len
            )));
        }
    }

    Ok(())
}

/// 使用循环缓冲区的OBV计算
#[cfg(target_arch = "x86_64")]
pub unsafe fn compute_obv_avx512(
    data: &VolumeData,
    ema_period: Option<usize>,
    chunk_size: Option<usize>,
) -> SimdResult<ObvResult> {
    // 验证输入参数
    validate_obv_inputs(data, ema_period)?;

    let len = data.close.len();
    let chunk_size = chunk_size.unwrap_or(1024); // 默认块大小
    let num_chunks = (len + chunk_size - 1) / chunk_size;

    // 使用Arc包装数据以便在线程间共享
    let data = Arc::new(data.clone());
    let mut result = ObvResult::with_capacity(len);
    result.obv.push(0.0); // 初始OBV值

    // 设置SIMD常量
    let zero_zmm = _mm512_setzero_pd();

    // 并行处理每个数据块
    let obv_chunks: Vec<Vec<f64>> = (0..num_chunks).into_par_iter().map(|chunk_idx| {
        let start = chunk_idx * chunk_size;
        let end = (start + chunk_size).min(len);
        let data = Arc::clone(&data);
        
        let mut chunk_obv = Vec::with_capacity(end - start);
        let mut running_obv = if chunk_idx == 0 { 0.0 } else { f64::NAN }; // NaN表示需要后续调整

        // SIMD处理当前块
        let simd_len = ((end - start) / 8) * 8;
        let mut i = start;

        while i < start + simd_len {
            // 加载价格数据
            let curr_price = _mm512_loadu_pd(&data.close[i]);
            let prev_price = _mm512_loadu_pd(&data.close[i-1]);
            let volume = _mm512_loadu_pd(&data.volume[i]);

            // 计算价格变化方向
            let price_diff = _mm512_sub_pd(curr_price, prev_price);
            let pos_mask = _mm512_cmp_pd_mask(price_diff, zero_zmm, _CMP_GT_OQ);
            let neg_mask = _mm512_cmp_pd_mask(price_diff, zero_zmm, _CMP_LT_OQ);

            // 根据价格变化调整成交量符号
            let signed_volume = _mm512_mask_mul_pd(
                _mm512_mask_mul_pd(volume, neg_mask, volume, _mm512_set1_pd(-1.0)),
                pos_mask,
                volume,
                _mm512_set1_pd(1.0)
            );

            // 存储结果
            let mut volume_arr = [0.0; 8];
            _mm512_storeu_pd(volume_arr.as_mut_ptr(), signed_volume);

            for vol in volume_arr.iter() {
                running_obv += vol;
                chunk_obv.push(running_obv);
            }

            i += 8;
        }

        // 处理剩余元素
        while i < end {
            let volume = data.volume[i];
            let sign = (data.close[i] - data.close[i-1]).signum();
            running_obv += sign * volume;
            chunk_obv.push(running_obv);
            i += 1;
        }

        chunk_obv
    }).collect();

    // 合并并调整各个块的结果
    let mut prev_obv = 0.0;
    for chunk in obv_chunks {
        for &obv in &chunk {
            if obv.is_nan() {
                result.obv.push(prev_obv);
            } else {
                result.obv.push(obv);
                prev_obv = obv;
            }
        }
    }

    // 如果需要计算EMA
    if let Some(period) = ema_period {
        let mut ema = Vec::with_capacity(len);
        let alpha = 2.0 / (period as f64 + 1.0);
        
        // 计算初始EMA
        let mut prev_ema = result.obv[0];
        ema.push(prev_ema);

        // SIMD计算EMA
        let alpha_zmm = _mm512_set1_pd(alpha);
        let one_minus_alpha_zmm = _mm512_set1_pd(1.0 - alpha);
        let simd_len = ((len - 1) / 8) * 8;
        let mut prev_ema_zmm = _mm512_set1_pd(prev_ema);

        for i in (1..simd_len + 1).step_by(8) {
            let obv_zmm = _mm512_loadu_pd(&result.obv[i]);
            
            let ema_zmm = _mm512_add_pd(
                _mm512_mul_pd(alpha_zmm, obv_zmm),
                _mm512_mul_pd(one_minus_alpha_zmm, prev_ema_zmm)
            );

            let mut ema_arr = [0.0; 8];
            _mm512_storeu_pd(ema_arr.as_mut_ptr(), ema_zmm);

            for &e in &ema_arr {
                ema.push(e);
                prev_ema = e;
            }

            prev_ema_zmm = ema_zmm;
        }

        // 处理剩余元素
        for i in simd_len + 1..len {
            prev_ema = alpha * result.obv[i] + (1.0 - alpha) * prev_ema;
            ema.push(prev_ema);
        }

        result.obv_ema = Some(ema);
    }

    // 验证结果
    result.validate()?;

    Ok(result)
}

/// 标量版本的OBV计算（后备实现）
pub fn compute_obv_fallback(
    data: &VolumeData,
    ema_period: Option<usize>,
) -> SimdResult<ObvResult> {
    // 验证输入参数
    validate_obv_inputs(data, ema_period)?;

    let len = data.close.len();
    let mut result = ObvResult::with_capacity(len);

    // 计算OBV
    result.obv.push(0.0); // 初始OBV值
    let mut running_obv = 0.0;

    for i in 1..len {
        let volume = data.volume[i];
        let sign = (data.close[i] - data.close[i-1]).signum();
        running_obv += sign * volume;
        result.obv.push(running_obv);
    }

    // 如果需要计算EMA
    if let Some(period) = ema_period {
        let mut ema = Vec::with_capacity(len);
        let alpha = 2.0 / (period as f64 + 1.0);
        
        // 计算EMA
        let mut prev_ema = result.obv[0];
        ema.push(prev_ema);

        for i in 1..len {
            prev_ema = alpha * result.obv[i] + (1.0 - alpha) * prev_ema;
            ema.push(prev_ema);
        }

        result.obv_ema = Some(ema);
    }

    // 验证结果
    result.validate()?;

    Ok(result)
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::time::Instant;

    fn generate_test_data(len: usize) -> VolumeData {
        let mut close = Vec::with_capacity(len);
        let mut volume = Vec::with_capacity(len);

        for i in 0..len {
            let price = 100.0 + (i as f64).sin() * 10.0;
            let vol = 1000.0 + (i as f64).cos() * 500.0;
            close.push(price);
            volume.push(vol);
        }

        VolumeData { close, volume }
    }

    #[test]
    fn test_obv_input_validation() {
        // 测试空输入
        let empty = VolumeData {
            close: vec![],
            volume: vec![],
        };
        let result = validate_obv_inputs(&empty, None);
        assert!(matches!(result, Err(SimdError::InvalidInputLength(_))));

        // 测试不一致的数组长度
        let inconsistent = VolumeData {
            close: vec![1.0, 2.0],
            volume: vec![1.0],
        };
        let result = validate_obv_inputs(&inconsistent, None);
        assert!(matches!(result, Err(SimdError::InvalidInputLength(_))));

        // 测试负数成交量
        let invalid_volume = VolumeData {
            close: vec![1.0, 2.0],
            volume: vec![1.0, -1.0],
        };
        let result = validate_obv_inputs(&invalid_volume, None);
        assert!(matches!(result, Err(SimdError::InvalidInputLength(_))));
    }

    #[test]
    fn test_obv_calculation() {
        let data = generate_test_data(1000);
        
        unsafe {
            // 测试基本OBV计算
            let result = compute_obv_avx512(&data, None, None);
            assert!(result.is_ok());
            let obv = result.unwrap();
            assert_eq!(obv.obv.len(), data.close.len());

            // 测试带EMA的OBV计算
            let result = compute_obv_avx512(&data, Some(14), None);
            assert!(result.is_ok());
            let obv = result.unwrap();
            assert!(obv.obv_ema.is_some());
            assert_eq!(obv.obv_ema.unwrap().len(), data.close.len());
        }
    }

    #[test]
    fn test_obv_compare_implementations() {
        let data = generate_test_data(1000);
        
        unsafe {
            let avx512_result = compute_obv_avx512(&data, Some(14), None).unwrap();
            let fallback_result = compute_obv_fallback(&data, Some(14)).unwrap();

            // 比较OBV值
            for i in 0..data.close.len() {
                assert!((avx512_result.obv[i] - fallback_result.obv[i]).abs() < 1e-10);
            }

            // 比较EMA值
            let avx512_ema = avx512_result.obv_ema.unwrap();
            let fallback_ema = fallback_result.obv_ema.unwrap();
            for i in 0..data.close.len() {
                assert!((avx512_ema[i] - fallback_ema[i]).abs() < 1e-10);
            }
        }
    }

    #[test]
    fn test_obv_performance() {
        // 生成大规模测试数据
        let sizes = [1000, 10000, 100000, 1000000];
        
        for &size in &sizes {
            let data = generate_test_data(size);
            
            // 测试AVX-512实现的性能
            let start = Instant::now();
            unsafe {
                let _ = compute_obv_avx512(&data, Some(14), None).unwrap();
            }
            let avx512_time = start.elapsed();

            // 测试标量实现的性能
            let start = Instant::now();
            let _ = compute_obv_fallback(&data, Some(14)).unwrap();
            let scalar_time = start.elapsed();

            println!("Size: {}, AVX-512: {:?}, Scalar: {:?}, Speedup: {:.2}x",
                size, avx512_time, scalar_time, 
                scalar_time.as_secs_f64() / avx512_time.as_secs_f64());
        }
    }

    #[test]
    fn test_obv_chunk_sizes() {
        let data = generate_test_data(100000);
        let chunk_sizes = [256, 512, 1024, 2048, 4096];
        
        unsafe {
            let baseline = compute_obv_avx512(&data, Some(14), None).unwrap();
            
            for &chunk_size in &chunk_sizes {
                let result = compute_obv_avx512(&data, Some(14), Some(chunk_size)).unwrap();
                
                // 验证结果一致性
                for i in 0..data.close.len() {
                    assert!((result.obv[i] - baseline.obv[i]).abs() < 1e-10);
                }
            }
        }
    }

    #[test]
    fn test_obv_parallel_performance() {
        let data = generate_test_data(1000000);
        let chunk_sizes = [256, 512, 1024, 2048, 4096];
        
        unsafe {
            for &chunk_size in &chunk_sizes {
                let start = Instant::now();
                let _ = compute_obv_avx512(&data, Some(14), Some(chunk_size)).unwrap();
                let parallel_time = start.elapsed();
                
                println!("Chunk size: {}, Time: {:?}", chunk_size, parallel_time);
            }
        }
    }
}